#include "generateur.h"

void MAI()
{
	addOperation(p_code, "MAI", 0, "0", " # Programme MAIN");
}

void STA(int deplacement)
{
	char val[5];
	sprintf(val, "%d", deplacement);
	addOperation(p_code, "STA", 0, val, " #Repositionnement de l'ancien contexte");
}

void LBA(int deplacement)
{
	char val[5];
	sprintf(val, "%d", deplacement);
	addOperation(p_code, "LBA", 0, val, " #Sauvegarde et positionnement du contexte");
}

void CAL(char name[128])
{
	struct func *f=getFunc(sav, name);
	char start[5];
	sprintf(start, "%d", f->start);
	char info[128]; sprintf(info, " #Appel a la fonction ou procedure %d", f->start);
	addOperation(p_code, "CAL", 0, start, info);
}

void RET(char name[128])
{
	addOperation(p_code, "RET", 0, "0", " #Return");
}

void OUT()
{
	struct element *first=depiler(pCompilation);
	char info[128]; sprintf(info, " #Affichage de %s=%s", first->nom, first->valeur);
	addOperation(p_code, "OUT", first->typeLiteral, "0", info);
}

void INC(int isMainProgram)
{
	struct element *e=depiler(pCompilation);
	char info[128]; sprintf(info, " #Depilage de %s=%s", e->nom, e->valeur);
	if(isMainProgram==0) //Uniquement si on est dans le programm principal
		addOperation(p_code, "INC", 0, "-1", info);
}

void INP(int typeL, char emplacementName[128])
{
	empiler(pCompilation, "Result Inp", "inp", -1, t_string, emplacementName); 
	addOperation(p_code, "INP", typeL, "0", " #Affichage");
}

void LOD(char varName[128], int typeI, int typeL, char emplacementName[128], int deplacement)
{
	char sDeplacement[5];
	sprintf(sDeplacement, "%d", deplacement);
	empiler(pCompilation, varName, pCompilation->base[deplacement]->valeur, typeI, typeL, emplacementName); 
	char info[128]; sprintf(info, " #Empilage identificateur %s; table des symbôles=%d", varName, deplacement);
	addOperation(p_code, "LOD", typeL, sDeplacement, info);
}

int LIT(char value[256], int typeI, int typeL, char emplacementName[128])
{
	empiler(pCompilation, "LIT", value, typeI, typeL, emplacementName);
	addOperation(p_code, "LIT", typeL, value, " #Empilage d'un literal");	
	
	return 0;	
}

int OPR(char comparaison[5])
{
	int typeOp=typePcode(comparaison);
	if(typeOp==-1) return ER_OP;

	char sTypeOp[5];
	struct element *first=depiler(pCompilation), *second=depiler(pCompilation);
	int resTypeOperation=0;

	if(typeOp==0 || typeOp==1 || typeOp==2 || typeOp==3)
	{
			switch(first->typeLiteral)
			{
				case t_entier:
					// cst_entier vs cst_entier ou cst_entier vs var_entier idem avec reel
					if(second->typeLiteral==t_entier){ 		 resTypeOperation=t_entier;}
					else if(second->typeLiteral==t_reel) 					resTypeOperation=t_reel;
					else if(second->typeLiteral==t_byte) 					resTypeOperation=t_entier;
					else return ER_TYPE;
					break;

				case t_reel:
					// cst_reel vs cst_entier ou cst_reel vs var_entier
					if(second->typeLiteral==t_entier || second->typeLiteral==t_reel)	resTypeOperation=t_reel;
					else return ER_TYPE;
					break;

				case t_string:
					if(typeOp==0 && (second->typeLiteral==t_string || second->typeLiteral==t_char))		        						resTypeOperation=t_string;
					else return ER_TYPE;
					break;

				case t_char:
					if(typeOp==0 && (second->typeLiteral==t_string || 
					second->typeLiteral==t_char))
						resTypeOperation=t_string;
					else return ER_TYPE;					
					break;

				case t_byte:
					if(second->typeLiteral==t_entier)					resTypeOperation=t_entier;
					else if(second->typeLiteral==t_byte)					resTypeOperation=t_byte;
					else return ER_TYPE;					
					break;
				default:
					return ER_TYPE;
			}
	}
	else if(typeOp==4 || typeOp==5 || typeOp==6 || typeOp==7 || typeOp==8 || typeOp==9)			resTypeOperation=t_boolean;
	else return ER_TYPE;

	if(typeOp==3) resTypeOperation=t_reel;

	sprintf(sTypeOp, "%d", typeOp);
	addOperation(p_code, "OPR", resTypeOperation, sTypeOp, " #Operation");
	empiler(pCompilation, "Tmp", "val", -1, resTypeOperation, " #Resultat op"); 
	return 0;
}

// Saut sans flag
void JMP(int line)
{
	char sLine[5];
	sprintf(sLine, "%d", line);

	addOperation(p_code, "JMP", 0, sLine, " #Saut inconditionnel");
}

// Saut avec flag
void JPC(int flag)
{
	addOperation(p_code, "JPC", flag, "-1", " #Saut conditionnel");
}

//Pas ok
void SFL()
{
	struct element *e=depiler(pCompilation);
	addOperation(p_code, "SFL", t_boolean, "-1", " #Set flag");
}

int STO(char varName[128], char nomEmplacement[128], int deplacement, int typeL, int typeI)
{
	char sDeplacement[5];
	int ok=0;
	sprintf(sDeplacement, "%d", deplacement);

	struct element *src=depiler(pCompilation);

	if(strcmp(src->nom, "Result inp")==0) // Cas lorsqu'on saisie une donnée, elle peut être de n'importe quel type, on ne l'analyse pas
	{
		return 0;
	}

	if(typeI==cst_entier || typeI==cst_reel || typeI==cst_char || typeI==cst_byte || typeI==cst_string || typeI==cst_boolean) 				return ER_AFFECTATION_STO_CST;

	switch(typeI)
	{
		case var_entier:
			// cst_entier vs cst_entier ou cst_entier vs var_entier idem avec reel
			if(src->typeLiteral==t_entier) ok=1;
			else if(src->typeLiteral==t_reel) ok=1;
			break;

		case var_reel:
			// cst_reel vs cst_entier ou cst_reel vs var_entier
			if(src->typeLiteral==t_entier) ok=1;
			else if(src->typeLiteral==t_reel) ok=1;
			break;

		case var_boolean:
			if(src->typeLiteral==t_boolean) ok=1;
			break;

		case var_string:
			if(src->typeLiteral==t_string || src->typeLiteral==t_char) ok=1;	
			break;

		case var_char:
			if(src->typeLiteral==t_char) ok=1;
			break;

		case var_byte:
			if(src->typeLiteral==t_entier || src->typeLiteral==t_byte) ok=1;
			break;
	}

	if(ok==1)
	{
		char info[128];
		sprintf(info, " #Affectation %s=%s a venant de %s", varName, src->valeur, src->nom);

		//Si la variable à charger est passé par référence
		struct symbole *select=chercherUnSymbole(tableSymbole, varName, -1, nomEmplacement);
		/*if(select->passage==passage_reference)
		FLR();*/
			addOperation(p_code, "STO", typeL, sDeplacement, info);
		return 0;
	}
	else return ER_AFFECTATION_STO;
}

void NOP()
{
	addOperation(p_code, "NOP", 0, "0", " #Instruction ne faisant rien");
}

int typePcode(char comparaison[5])
{
	if(strcmp(comparaison, "+")==0) return 0;
	else if(strcmp(comparaison, "-")==0) return 1;
	else if(strcmp(comparaison, "*")==0) return 2;
	else if(strcmp(comparaison, "/")==0) return 3;
	else if(strcmp(comparaison, "<")==0) return 4;
	else if(strcmp(comparaison, "<=")==0) return 5;
	else if(strcmp(comparaison, ">")==0) return 6;
	else if(strcmp(comparaison, ">=")==0) return 7;
	else if(strcmp(comparaison, "<>")==0) return 8;
	else if(strcmp(comparaison, "=")==0) return 9;
	else return -1;
}
